﻿/**************************************************************
 *
 * 唯一标识：c70e01a0-b152-47ed-be07-35b6ea5a6c17
 * 命名空间：Sgr.UPMS.Domain.Departments
 * 创建时间：2023/8/27 19:42:32
 * 机器名称：DESKTOP-S0D075D
 * 创建者：antho
 * 电子邮箱：fengqinhua2016@163.com
 * 描述：
 *
 **************************************************************/

using Sgr.Domain.Entities;
using Sgr.Domain.Managers;
using Sgr.Domain.Repositories;
using Sgr.Exceptions;
using Sgr.Generator;
using Sgr.UPMS.Domain.Menus;
using Sgr.UPMS.Domain.Organizations;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Sgr.UPMS.Domain.Departments
{
    /// <summary>
    /// 部门管理实现类
    /// </summary>
    public class DepartmentManage : TreeNodeManageBase<Department, long>, IDepartmentManage
    {
        private readonly ISegmentNumIdGenerator _numberIdGenerator;

        /// <summary>
        /// 添加一个属性来安全地转换基类的仓储引用
        /// </summary>
        private IDepartmentRepository DepartmentRepository =>
            (IDepartmentRepository)_repository;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="repository">部门仓储</param>
        /// <param name="numberIdGenerator">ID生成器</param>
        public DepartmentManage(
            IDepartmentRepository repository,
            ISegmentNumIdGenerator numberIdGenerator) : base(repository)
        {
            _numberIdGenerator = numberIdGenerator ?? throw new ArgumentNullException(nameof(numberIdGenerator));
        }

        /// <summary>
        /// 创建新的部门
        /// <para>规则1：同级部门名称唯一性</para>
        /// <para>规则2：部门层级不超过5级</para>
        /// <para>规则3：父部门必须处于正常状态</para>
        /// <para>规则4：组织权限控制</para>
        /// </summary>
        /// <param name="name">部门名称</param>
        /// <param name="orderNumber">排序序号</param>
        /// <param name="entityStates">部门状态</param>
        /// <param name="remarks">备注</param>
        /// <param name="managerUserId">主管Id</param>
        /// <param name="leader">负责人</param>
        /// <param name="phone">联系电话</param>
        /// <param name="email">联系邮箱</param>
        /// <param name="orgId">组织ID</param>
        /// <param name="parentId">父部门ID</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>新创建的部门</returns>
        public async Task<Department> CreateNewAsync(
            string name,
            int orderNumber,
            EntityStates entityStates,
            string? remarks,
            long? managerUserId,
            string? leader,
            string? phone,
            string? email,
            long orgId,
            long? parentId,
            CancellationToken cancellationToken = default)
        {
            Check.StringNotNullOrWhiteSpace(name, nameof(name));

            if (entityStates == EntityStates.None)
                throw DomainException.ValidationError("部门状态未设置");

            // 处理父级节点
            parentId ??= 0;

            // 验证同级部门名称唯一性
            var nameUniquenessResult = await ValidateNameUniquenessAsync(orgId, name, parentId.Value, null, cancellationToken);
            if (!nameUniquenessResult.IsComply)
                throw DomainException.ValidationError(nameUniquenessResult.Message);

            // 获取Id
            var id = await _numberIdGenerator.GetUniqueIdAsync(UpmsConstant.DEFAULT_SEGMENT_KEY, cancellationToken);

            // 如果有父节点，验证父节点存在且状态合适
            Department? parentNode = null;
            if (parentId > 0)
            {
                parentNode = await DepartmentRepository.GetAsync(parentId.Value, cancellationToken);
                if (parentNode == null)
                    throw DomainException.ValidationError($"上级部门ID {parentId} 不存在");

                if (parentNode.State == EntityStates.Deactivate)
                    throw DomainException.ValidationError($"上级部门 {parentNode.Name} 已停用，请先激活上级部门。");

                // 验证组织权限
                if (parentNode.OrgId != orgId)
                    throw DomainException.ValidationError("无权限在该上级部门下创建子部门");
            }

            // 生成节点路径（最大层级限制为5）
            string nodePath = GetNodePath(parentNode, id, 5);

            // 创建部门实例
            var entity = new Department(Guid.NewGuid().ToString("N"), name, orderNumber, remarks, orgId)
            {
                Id = id
            };
            entity.ChangeManagerUser(managerUserId, leader, phone, email);
            entity.ChangeState(entityStates);
            entity.SetParent(parentId.Value, nodePath);

            return entity;
        }

        /// <summary>
        /// 验证同级部门名称是否唯一
        /// </summary>
        /// <param name="orgId">组织Id</param>
        /// <param name="name">部门名称</param>
        /// <param name="parentId">父级部门ID</param>
        /// <param name="excludeId">需要排除的部门ID</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>业务规则检查结果</returns>
        public async Task<DomainRuleCheckResult> ValidateNameUniquenessAsync(
            long orgId,
            string name,
            long parentId,
            long? excludeId = null,
            CancellationToken cancellationToken = default)
        {
            if (await DepartmentRepository.IsNameExistsInSameLevelAsync(orgId, name, parentId, excludeId, cancellationToken))
                return DomainRuleCheckResult.Fail($"同级部门下已存在名称为 '{name}' 的部门");

            return DomainRuleCheckResult.Ok();
        }

        /// <summary>
        /// 激活部门及其子部门
        /// </summary>
        /// <param name="department">部门</param>
        /// <param name="cancellationToken">取消令牌</param>
        public async Task ActivateAsync(Department department, CancellationToken cancellationToken = default)
        {
            Check.NotNull(department, nameof(department));

            if (department.State == EntityStates.Normal)
                return;

            // 查找当前部门的上级部门，如果上级部门存在且处于停用状态，则抛出异常
            if (department.ParentId != 0)
            {
                var parentDepartment = await DepartmentRepository.GetAsync(department.ParentId, cancellationToken);
                if (parentDepartment != null && parentDepartment.State == EntityStates.Deactivate)
                    throw DomainException.LimitExceededError($"上级部门 {parentDepartment.Name} 已停用，请先激活上级部门。");
            }

            await SetDepartmentStateAsync(department, EntityStates.Normal, cancellationToken);
        }

        /// <summary>
        /// 停用部门及其子部门
        /// </summary>
        /// <param name="department">部门</param>
        /// <param name="cancellationToken">取消令牌</param>
        public async Task DeactivateAsync(Department department, CancellationToken cancellationToken = default)
        {
            Check.NotNull(department, nameof(department));

            if (department.State == EntityStates.Deactivate)
                return;

            await SetDepartmentStateAsync(department, EntityStates.Deactivate, cancellationToken);
        }

        /// <summary>
        /// 重写基类中验证移动操作是否有效的验证规则
        /// </summary>
        /// <param name="sourceNode">源节点</param>
        /// <param name="targetId">目标节点ID</param>
        /// <param name="maxLevel">最大层级限制</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>验证结果</returns>
        public override async Task<DomainRuleCheckResult> ValidateMoveOperationAsync(
            Department sourceNode,
            long targetId,
            int maxLevel = 5,
            CancellationToken cancellationToken = default)
        {
            // 如果目标ID是0，表示移动到根节点，这是合法的
            if (targetId == 0)
                return DomainRuleCheckResult.Ok();

            // 检查目标节点是否存在
            var targetNode = await DepartmentRepository.GetAsync(targetId, cancellationToken);
            if (targetNode == null)
                return DomainRuleCheckResult.Fail($"目标节点(ID:{targetId})不存在");

            // 源节点不能是目标节点的父节点或祖先节点
            if (targetNode.NodePath.Contains($"/{sourceNode.Id}/"))
                return DomainRuleCheckResult.Fail("不能将节点移动到其子节点或后代节点下");

            // 校验目标节点层级是否已达到最大限制
            if (targetNode.NodePath.Split('/').Length >= maxLevel)
                return DomainRuleCheckResult.Fail($"目标节点已达到最大层级限制({maxLevel})，无法移动");

            // 验证组织权限
            if (targetNode.OrgId != sourceNode.OrgId)
                return DomainRuleCheckResult.Fail("不能将部门移动到不同组织的部门下");

            // 验证同级名称唯一性
            var nameUniquenessResult = await ValidateNameUniquenessAsync(
                sourceNode.OrgId,
                sourceNode.Name,
                targetId,
                sourceNode.Id,
                cancellationToken);
            if (!nameUniquenessResult.IsComply)
                return nameUniquenessResult;

            return DomainRuleCheckResult.Ok();
        }

        /// <summary>
        /// 设置部门状态为指定的实体状态，并更新该部门及其所有子部门的状态
        /// </summary>
        /// <param name="department">部门</param>
        /// <param name="entityStates">实体状态</param>
        /// <param name="cancellationToken">取消令牌</param>
        private async Task SetDepartmentStateAsync(Department department, EntityStates entityStates, CancellationToken cancellationToken)
        {
            department.ChangeState(entityStates);
            await DepartmentRepository.UpdateAsync(department, cancellationToken);

            var children = await DepartmentRepository.GetChildNodesRecursionAsync(department.NodePath, cancellationToken);
            foreach (var child in children)
            {
                child.ChangeState(entityStates);
                await DepartmentRepository.UpdateAsync(child, cancellationToken);
            }
        }

        /// <summary>
        /// 删除某个节点前的操作
        /// </summary>
        /// <param name="entity">要删除的实体</param>
        protected override void BeforeDeleteEntity(Department entity)
        {
            base.BeforeDeleteEntity(entity);

            // 删除前标记为删除状态
            entity.MarkAsDeleted();
        }

        /// <summary>
        /// 修改树节点的父节点
        /// </summary>
        /// <param name="entity">要修改的实体</param>
        /// <param name="parentEntity">新的父实体</param>
        /// <param name="maxLevel">最大层级限制</param>
        protected override void ChangeEntityParent(Department entity, Department? parentEntity, int maxLevel = 5)
        {
            long parentId = 0;
            if (parentEntity != null)
            {
                parentId = parentEntity.Id;
            }

            string path = GetNodePath(parentEntity, entity.Id, maxLevel);

            entity.SetParent(parentId, path);
        }

        ///// <summary>
        ///// 验证是否可以删除指定的部门
        ///// </summary>
        ///// <param name="departmentId">部门ID</param>
        ///// <param name="cancellationToken">取消令牌</param>
        ///// <returns>验证结果</returns>
        //public async Task<DomainRuleCheckResult> ValidateDeleteAsync(long departmentId, CancellationToken cancellationToken = default)
        //{
        //    var department = await DepartmentRepository.GetAsync(departmentId, cancellationToken);
        //    if (department == null)
        //        return DomainRuleCheckResult.Fail("部门不存在");

        //    // 检查是否有子部门
        //    var hasChildren = await DepartmentRepository.HasChildNodesAsync(department, cancellationToken);
        //    if (hasChildren)
        //        return DomainRuleCheckResult.Fail("存在子部门，无法删除");

        //    // 这里可以添加更多业务规则检查
        //    // 例如：检查是否有员工在此部门
        //    // var hasEmployees = await _employeeRepository.HasEmployeesByDepartmentAsync(departmentId, cancellationToken);
        //    // if (hasEmployees)
        //    //     return DomainRuleCheckResult.Fail("存在关联员工，无法删除");

        //    return DomainRuleCheckResult.Ok();
        //}

        ///// <summary>
        ///// 批量更新部门状态
        ///// </summary>
        ///// <param name="departmentIds">部门ID列表</param>
        ///// <param name="state">目标状态</param>
        ///// <param name="cancellationToken">取消令牌</param>
        ///// <returns>更新结果</returns>
        //public async Task<bool> BatchUpdateStateAsync(
        //    IEnumerable<long> departmentIds,
        //    EntityStates state,
        //    CancellationToken cancellationToken = default)
        //{
        //    foreach (var departmentId in departmentIds)
        //    {
        //        var department = await DepartmentRepository.GetAsync(departmentId, cancellationToken);
        //        if (department != null)
        //        {
        //            if (state == EntityStates.Normal)
        //                await ActivateAsync(department, cancellationToken);
        //            else if (state == EntityStates.Deactivate)
        //                await DeactivateAsync(department, cancellationToken);
        //        }
        //    }

        //    return true;
        //}
    }
}